package no.uib.hplims.jobs;

import java.util.List;
import java.util.concurrent.Callable;

import org.vaadin.appfoundation.persistence.facade.FacadeFactory;

import no.uib.hplims.models.BlastSearch;
import no.uib.hplims.models.MyOrder;
import no.uib.hplims.tools.events.BlastSubmitFinishedEvent;
import no.uib.hplims.tools.events.BlastSubmitFinishedListener;

import uk.ac.ebi.kraken.model.blast.parameters.DatabaseOptions;
import uk.ac.ebi.kraken.model.blast.parameters.GapAlign;
import uk.ac.ebi.kraken.model.blast.parameters.SimilarityMatrixOptions;
import uk.ac.ebi.kraken.uuw.services.remoting.UniProtJAPI;
import uk.ac.ebi.kraken.uuw.services.remoting.UniProtQueryService;
import uk.ac.ebi.kraken.uuw.services.remoting.blast.BlastInput;

public class SubmitBlastSearchJob implements Callable<Object> {

	// Create the listener list
	protected javax.swing.event.EventListenerList listenerList = new javax.swing.event.EventListenerList();

	private Enum[] blastParams = null;
	private String species = null;

	public SubmitBlastSearchJob(List<String> sequences, MyOrder order,
			String species) {
		this.species = species;
		storeSequencesToDB(sequences, order, species, BlastSearch.BLAST_SEARCH_NEW);

	}

	public SubmitBlastSearchJob(List<String> sequences, MyOrder order,
			String species, Enum... params) {
		this.species = species;
		this.blastParams = params;
		storeSequencesToDB(sequences, order, species, BlastSearch.BLAST_SEARCH_UPDATE);

	}

	private void storeSequencesToDB(List<String> seqs, MyOrder order, String species,
			String mode) {

		for (String s : seqs) {
			BlastSearch bs = new BlastSearch(s, order, species, mode);
			FacadeFactory.getFacade().store(bs);
		}

	}

	// This methods allows classes to register for BlastSubmitFinishedEvents
	public void addListener(BlastSubmitFinishedListener listener) {
		listenerList.add(BlastSubmitFinishedListener.class, listener);
	}

	// This methods allows classes to unregister for BlastSubmitFinishedEvents
	public void removeListener(BlastSubmitFinishedListener listener) {
		listenerList.remove(BlastSubmitFinishedListener.class, listener);
	}

	// This private class is used to fire BlastSubmitFinishedEvents
	void fireBlastSubmitFinishedEvent(BlastSubmitFinishedEvent evt) {
		Object[] listeners = listenerList.getListenerList();
		// Each listener occupies two elements - the first is the listener class
		// and the second is the listener instance
		for (int i = 0; i < listeners.length; i += 2) {
			if (listeners[i] == BlastSubmitFinishedListener.class) {
				((BlastSubmitFinishedListener) listeners[i + 1])
						.eventOccurred(evt);
			}
		}
	}

	public Object call() throws Exception {

		System.out.println("---STARTING SUBMIT---");

		List<BlastSearch> sequences = FacadeFactory.getFacade().list(
				BlastSearch.class);

		UniProtQueryService service = UniProtJAPI.factory
				.getUniProtQueryService();

		for (BlastSearch bs : sequences) {

			if (!bs.isSubmitted()) {

				String querySequence = bs.getQuery();

				BlastInput input = null;

				if (blastParams == null || blastParams.length == 0) {
					// Create a blast input with a Database and a
					// peptideSequence
					input = new BlastInput(DatabaseOptions.SWISSPROT,
							querySequence, GapAlign.FALSE,
							SimilarityMatrixOptions.PAM_30); // PAM_30 for query
																// length
																// shorter than
																// 35
																// (see
																// http://web.expasy.org/blast/blast_help.html
																// - Options:
																// Comparison
																// matrix)
				} else if (blastParams.length == 1) {
					input = new BlastInput(DatabaseOptions.SWISSPROT,
							querySequence, GapAlign.FALSE,
							SimilarityMatrixOptions.PAM_30, blastParams[0]);
				} else {
					System.out.println("Parameters need configuration");
					return null;
				}

				// Submitting the input to the service will return a job id
				String jobID = service.submitBlast(input);

				if (jobID != null && !jobID.isEmpty()) {
					bs.setJobID(jobID);
					bs.setSubmitted(true);

					FacadeFactory.getFacade().store(bs);

					System.out.println("Job submitted for " + querySequence
							+ ". ID = " + jobID);
				}

				try {
					// Sleep before next request
					Thread.sleep(100);
					System.out.println("Sleeping 150ms");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("Done sleeping.");
			}
		}

		// Sleep for 3 seconds before polling for results
		try {
			// Sleep before next request
			System.out.println("Sleeping 3000ms");
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("---SUBMIT FINISHED---");

		// Notify listeners that all sequences have been submitted to UniProt
		fireBlastSubmitFinishedEvent(new BlastSubmitFinishedEvent(this));

		return null;
	}

}
